/*
 * Copyright (C) 2006 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package me.pcqpcq.android.adapter;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import me.pcqpcq.android.aclean.R;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.ExpandableListView;
import android.widget.ImageView;
import android.widget.TextView;

/**
 * An easy adapter to map static data to group and child views defined in an XML
 * file. You can separately specify the data backing the group as a List of
 * Maps. Each entry in the ArrayList corresponds to one group in the expandable
 * list. The Maps contain the data for each row. You also specify an XML file
 * that defines the views used to display a group, and a mapping from keys in
 * the Map to specific views. This process is similar for a child, except it is
 * one-level deeper so the data backing is specified as a List<List<Map>>,
 * where the first List corresponds to the group of the child, the second List
 * corresponds to the position of the child within the group, and finally the
 * Map holds the data for that particular child.
 */
public class SimpleCleanExpanListAdapter extends BaseExpandableListAdapter {
	private List<? extends Map<String, ?>> mGroupData;
	private int mExpandedGroupLayout;
	private int mCollapsedGroupLayout;
	private String[] mGroupFrom;
	private int[] mGroupTo;

	private List<? extends List<? extends Map<String, ?>>> mChildData;
	private int mChildLayout;
	private int mLastChildLayout;
	private String[] mChildFrom;
	private int[] mChildTo;

	private Map<Integer, LinkedList<Integer>> mSelected = new HashMap<Integer, LinkedList<Integer>>();

	private LayoutInflater mInflater;

	/**
	 * Constructor
	 * 
	 * @param context The context where the {@link ExpandableListView}
	 *            associated with this {@link SimpleCleanExpanListAdapter} is
	 *            running
	 * @param groupData A List of Maps. Each entry in the List corresponds to
	 *            one group in the list. The Maps contain the data for each
	 *            group, and should include all the entries specified in
	 *            "groupFrom"
	 * @param groupFrom A list of keys that will be fetched from the Map
	 *            associated with each group.
	 * @param groupTo The group views that should display column in the
	 *            "groupFrom" parameter. These should all be TextViews. The
	 *            first N views in this list are given the values of the first N
	 *            columns in the groupFrom parameter.
	 * @param groupLayout resource identifier of a view layout that defines the
	 *            views for a group. The layout file should include at least
	 *            those named views defined in "groupTo"
	 * @param childData A List of List of Maps. Each entry in the outer List
	 *            corresponds to a group (index by group position), each entry
	 *            in the inner List corresponds to a child within the group
	 *            (index by child position), and the Map corresponds to the data
	 *            for a child (index by values in the childFrom array). The Map
	 *            contains the data for each child, and should include all the
	 *            entries specified in "childFrom"
	 * @param childFrom A list of keys that will be fetched from the Map
	 *            associated with each child.
	 * @param childTo The child views that should display column in the
	 *            "childFrom" parameter. These should all be TextViews. The
	 *            first N views in this list are given the values of the first N
	 *            columns in the childFrom parameter.
	 * @param childLayout resource identifier of a view layout that defines the
	 *            views for a child. The layout file should include at least
	 *            those named views defined in "childTo"
	 */
	public SimpleCleanExpanListAdapter(Context context, List<? extends Map<String, ?>> groupData, int groupLayout,
			String[] groupFrom, int[] groupTo, List<? extends List<? extends Map<String, ?>>> childData,
			int childLayout, String[] childFrom, int[] childTo) {
		this(context, groupData, groupLayout, groupLayout, groupFrom, groupTo, childData, childLayout, childLayout,
				childFrom, childTo);
	}

	/**
	 * Constructor
	 * 
	 * @param context The context where the {@link ExpandableListView}
	 *            associated with this {@link SimpleCleanExpanListAdapter} is
	 *            running
	 * @param groupData A List of Maps. Each entry in the List corresponds to
	 *            one group in the list. The Maps contain the data for each
	 *            group, and should include all the entries specified in
	 *            "groupFrom"
	 * @param groupFrom A list of keys that will be fetched from the Map
	 *            associated with each group.
	 * @param groupTo The group views that should display column in the
	 *            "groupFrom" parameter. These should all be TextViews. The
	 *            first N views in this list are given the values of the first N
	 *            columns in the groupFrom parameter.
	 * @param expandedGroupLayout resource identifier of a view layout that
	 *            defines the views for an expanded group. The layout file
	 *            should include at least those named views defined in "groupTo"
	 * @param collapsedGroupLayout resource identifier of a view layout that
	 *            defines the views for a collapsed group. The layout file
	 *            should include at least those named views defined in "groupTo"
	 * @param childData A List of List of Maps. Each entry in the outer List
	 *            corresponds to a group (index by group position), each entry
	 *            in the inner List corresponds to a child within the group
	 *            (index by child position), and the Map corresponds to the data
	 *            for a child (index by values in the childFrom array). The Map
	 *            contains the data for each child, and should include all the
	 *            entries specified in "childFrom"
	 * @param childFrom A list of keys that will be fetched from the Map
	 *            associated with each child.
	 * @param childTo The child views that should display column in the
	 *            "childFrom" parameter. These should all be TextViews. The
	 *            first N views in this list are given the values of the first N
	 *            columns in the childFrom parameter.
	 * @param childLayout resource identifier of a view layout that defines the
	 *            views for a child. The layout file should include at least
	 *            those named views defined in "childTo"
	 */
	public SimpleCleanExpanListAdapter(Context context, List<? extends Map<String, ?>> groupData,
			int expandedGroupLayout, int collapsedGroupLayout, String[] groupFrom, int[] groupTo,
			List<? extends List<? extends Map<String, ?>>> childData, int childLayout, String[] childFrom, int[] childTo) {
		this(context, groupData, expandedGroupLayout, collapsedGroupLayout, groupFrom, groupTo, childData, childLayout,
				childLayout, childFrom, childTo);
	}

	/**
	 * Constructor
	 * 
	 * @param context The context where the {@link ExpandableListView}
	 *            associated with this {@link SimpleCleanExpanListAdapter} is
	 *            running
	 * @param groupData A List of Maps. Each entry in the List corresponds to
	 *            one group in the list. The Maps contain the data for each
	 *            group, and should include all the entries specified in
	 *            "groupFrom"
	 * @param groupFrom A list of keys that will be fetched from the Map
	 *            associated with each group.
	 * @param groupTo The group views that should display column in the
	 *            "groupFrom" parameter. These should all be TextViews. The
	 *            first N views in this list are given the values of the first N
	 *            columns in the groupFrom parameter.
	 * @param expandedGroupLayout resource identifier of a view layout that
	 *            defines the views for an expanded group. The layout file
	 *            should include at least those named views defined in "groupTo"
	 * @param collapsedGroupLayout resource identifier of a view layout that
	 *            defines the views for a collapsed group. The layout file
	 *            should include at least those named views defined in "groupTo"
	 * @param childData A List of List of Maps. Each entry in the outer List
	 *            corresponds to a group (index by group position), each entry
	 *            in the inner List corresponds to a child within the group
	 *            (index by child position), and the Map corresponds to the data
	 *            for a child (index by values in the childFrom array). The Map
	 *            contains the data for each child, and should include all the
	 *            entries specified in "childFrom"
	 * @param childFrom A list of keys that will be fetched from the Map
	 *            associated with each child.
	 * @param childTo The child views that should display column in the
	 *            "childFrom" parameter. These should all be TextViews. The
	 *            first N views in this list are given the values of the first N
	 *            columns in the childFrom parameter.
	 * @param childLayout resource identifier of a view layout that defines the
	 *            views for a child (unless it is the last child within a group,
	 *            in which case the lastChildLayout is used). The layout file
	 *            should include at least those named views defined in "childTo"
	 * @param lastChildLayout resource identifier of a view layout that defines
	 *            the views for the last child within each group. The layout
	 *            file should include at least those named views defined in
	 *            "childTo"
	 */
	public SimpleCleanExpanListAdapter(Context context, List<? extends Map<String, ?>> groupData,
			int expandedGroupLayout, int collapsedGroupLayout, String[] groupFrom, int[] groupTo,
			List<? extends List<? extends Map<String, ?>>> childData, int childLayout, int lastChildLayout,
			String[] childFrom, int[] childTo) {
		mGroupData = groupData;
		mExpandedGroupLayout = expandedGroupLayout;
		mCollapsedGroupLayout = collapsedGroupLayout;
		mGroupFrom = groupFrom;
		mGroupTo = groupTo;

		mChildData = childData;
		mChildLayout = childLayout;
		mLastChildLayout = lastChildLayout;
		mChildFrom = childFrom;
		mChildTo = childTo;

		mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
	}

	public Object getChild(int groupPosition, int childPosition) {
		return mChildData.get(groupPosition).get(childPosition);
	}

	public long getChildId(int groupPosition, int childPosition) {
		return childPosition;
	}

	public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView,
			ViewGroup parent) {
		View v;
		if (convertView == null) {
			v = newChildView(isLastChild, parent);
		} else {
			v = convertView;
		}

		// 添加勾选框的点击监听器
		ImageView imageView = (ImageView) v.findViewById(R.id.listview_check);
		if (imageView != null)
			imageView.setOnClickListener(new CheckBtnClickListener(imageView, groupPosition, childPosition));

		bindView(v, mChildData.get(groupPosition).get(childPosition), mChildFrom, mChildTo);
		return v;
	}

	/**
	 * Instantiates a new View for a child.
	 * @param isLastChild Whether the child is the last child within its group.
	 * @param parent The eventual parent of this new View.
	 * @return A new child View
	 */
	public View newChildView(boolean isLastChild, ViewGroup parent) {
		return mInflater.inflate((isLastChild) ? mLastChildLayout : mChildLayout, parent, false);
	}

	private void bindView(View view, Map<String, ?> data, String[] from, int[] to) {
		int len = to.length;

		for (int i = 0; i < len; i++) {
			TextView v = (TextView) view.findViewById(to[i]);
			if (v != null) {
				v.setText((String) data.get(from[i]));
			}
		}
	}

	public int getChildrenCount(int groupPosition) {
		return mChildData.get(groupPosition).size();
	}

	public Object getGroup(int groupPosition) {
		return mGroupData.get(groupPosition);
	}

	public int getGroupCount() {
		return mGroupData.size();
	}

	public long getGroupId(int groupPosition) {
		return groupPosition;
	}

	public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
		View v;
		if (convertView == null) {
			v = newGroupView(isExpanded, parent);
		} else {
			v = convertView;
		}
		bindView(v, mGroupData.get(groupPosition), mGroupFrom, mGroupTo);
		return v;
	}

	/**
	 * Instantiates a new View for a group.
	 * @param isExpanded Whether the group is currently expanded.
	 * @param parent The eventual parent of this new View.
	 * @return A new group View
	 */
	public View newGroupView(boolean isExpanded, ViewGroup parent) {
		return mInflater.inflate((isExpanded) ? mExpandedGroupLayout : mCollapsedGroupLayout, parent, false);
	}

	public boolean isChildSelectable(int groupPosition, int childPosition) {
		return true;
	}

	public boolean hasStableIds() {
		return true;
	}

	protected class CheckBtnClickListener implements OnClickListener {

		private ImageView imageView;
		private int groupPosition;
		private int childPosition;

		public CheckBtnClickListener(ImageView imageView, int groupPosition, int childPosition) {
			this.imageView = imageView;
			this.groupPosition = groupPosition;
			this.childPosition = childPosition;
		}

		@Override
		public void onClick(View v) {
			if (!(mSelected.containsKey(groupPosition))) {
				LinkedList<Integer> childList = new LinkedList<Integer>();
				childList.add(childPosition);
				mSelected.put(groupPosition, childList);
				imageView.setBackgroundResource(R.drawable.btn_check_on);
			} else {
				LinkedList<Integer> childList = mSelected.get((Integer) groupPosition);
				if (!childList.contains((Integer) childPosition)) {
					childList.add(childPosition);
					imageView.setBackgroundResource(R.drawable.btn_check_on);
				} else {
					childList.remove((Integer) childPosition);
					imageView.setBackgroundResource(R.drawable.btn_check_off);
				}
			}
		}
	}

}
